From 8511033169d1ff3b8eb7b9c32c496d9fccb1f364 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Mon, 10 Jan 2005 18:37:09 +0000 Subject: [PATCH] Fix #162617. 2005-01-10 Federico Mena Quintero Fix #162617. * gtk/gtkfilesystemunix.c (STAT_NEEDED_MASK): Take out GTK_FILE_INFO_IS_HIDDEN; we don't need to stat() to know this. (gtk_file_system_unix_get_folder): Make error reporting more accurate. Don't bail out if we can't read the directory. (fill_in_stats): Don't return an error; just assume we don't have stat info for this folder's files. (fill_in_names): Don't create the hash table for the names if we can't open the directory. (gtk_file_folder_unix_list_children): Don't emit the "finished-loading" signal --- we don't do asynchronous loads, so we are always finished loading. (gtk_file_folder_unix_get_info): Use helper functions; handle the case where we can't stat '/'. (get_icon_type_from_path): Don't call fill_in_stats() here; only use the info we have. (fill_in_mime_type): Don't return an error. Don't do anything if we don't have the stat info. --- ChangeLog | 22 +++ ChangeLog.pre-2-10 | 22 +++ ChangeLog.pre-2-8 | 22 +++ gtk/gtkfilesystemunix.c | 348 ++++++++++++++++++++++++++-------------- 4 files changed, 295 insertions(+), 119 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b51a4f47d..0d2f06a1e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2005-01-10 Federico Mena Quintero + + Fix #162617. + + * gtk/gtkfilesystemunix.c (STAT_NEEDED_MASK): Take out + GTK_FILE_INFO_IS_HIDDEN; we don't need to stat() to know this. + (gtk_file_system_unix_get_folder): Make error reporting more + accurate. Don't bail out if we can't read the directory. + (fill_in_stats): Don't return an error; just assume we don't have + stat info for this folder's files. + (fill_in_names): Don't create the hash table for the names if we + can't open the directory. + (gtk_file_folder_unix_list_children): Don't emit the + "finished-loading" signal --- we don't do asynchronous loads, so + we are always finished loading. + (gtk_file_folder_unix_get_info): Use helper functions; handle the + case where we can't stat '/'. + (get_icon_type_from_path): Don't call fill_in_stats() here; only + use the info we have. + (fill_in_mime_type): Don't return an error. Don't do anything if + we don't have the stat info. + 2005-01-10 Owen Taylor * Makefile.am (EXTRA_DIST): Adding missing ChangeLog.pre* diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 3b51a4f47d..0d2f06a1e3 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,25 @@ +2005-01-10 Federico Mena Quintero + + Fix #162617. + + * gtk/gtkfilesystemunix.c (STAT_NEEDED_MASK): Take out + GTK_FILE_INFO_IS_HIDDEN; we don't need to stat() to know this. + (gtk_file_system_unix_get_folder): Make error reporting more + accurate. Don't bail out if we can't read the directory. + (fill_in_stats): Don't return an error; just assume we don't have + stat info for this folder's files. + (fill_in_names): Don't create the hash table for the names if we + can't open the directory. + (gtk_file_folder_unix_list_children): Don't emit the + "finished-loading" signal --- we don't do asynchronous loads, so + we are always finished loading. + (gtk_file_folder_unix_get_info): Use helper functions; handle the + case where we can't stat '/'. + (get_icon_type_from_path): Don't call fill_in_stats() here; only + use the info we have. + (fill_in_mime_type): Don't return an error. Don't do anything if + we don't have the stat info. + 2005-01-10 Owen Taylor * Makefile.am (EXTRA_DIST): Adding missing ChangeLog.pre* diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 3b51a4f47d..0d2f06a1e3 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,25 @@ +2005-01-10 Federico Mena Quintero + + Fix #162617. + + * gtk/gtkfilesystemunix.c (STAT_NEEDED_MASK): Take out + GTK_FILE_INFO_IS_HIDDEN; we don't need to stat() to know this. + (gtk_file_system_unix_get_folder): Make error reporting more + accurate. Don't bail out if we can't read the directory. + (fill_in_stats): Don't return an error; just assume we don't have + stat info for this folder's files. + (fill_in_names): Don't create the hash table for the names if we + can't open the directory. + (gtk_file_folder_unix_list_children): Don't emit the + "finished-loading" signal --- we don't do asynchronous loads, so + we are always finished loading. + (gtk_file_folder_unix_get_info): Use helper functions; handle the + case where we can't stat '/'. + (get_icon_type_from_path): Don't call fill_in_stats() here; only + use the info we have. + (fill_in_mime_type): Don't return an error. Don't do anything if + we don't have the stat info. + 2005-01-10 Owen Taylor * Makefile.am (EXTRA_DIST): Adding missing ChangeLog.pre* diff --git a/gtk/gtkfilesystemunix.c b/gtk/gtkfilesystemunix.c index d6cf88fc1c..f84ec0fda9 100644 --- a/gtk/gtkfilesystemunix.c +++ b/gtk/gtkfilesystemunix.c @@ -115,7 +115,6 @@ struct stat_info_entry { }; static const GtkFileInfoType STAT_NEEDED_MASK = (GTK_FILE_INFO_IS_FOLDER | - GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_MODIFICATION_TIME | GTK_FILE_INFO_SIZE); @@ -215,8 +214,8 @@ static GtkFilePath *filename_to_path (const gchar *filename); static gboolean filename_is_root (const char *filename); static gboolean fill_in_names (GtkFileFolderUnix *folder_unix, GError **error); -static gboolean fill_in_stats (GtkFileFolderUnix *folder_unix, GError **error); -static gboolean fill_in_mime_type (GtkFileFolderUnix *folder_unix, GError **error); +static void fill_in_stats (GtkFileFolderUnix *folder_unix); +static void fill_in_mime_type (GtkFileFolderUnix *folder_unix); static char * get_parent_dir (const char *filename); @@ -406,29 +405,41 @@ gtk_file_system_unix_get_folder (GtkFileSystem *file_system, } else { - if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + struct stat statbuf; + int result; + int code; + int my_errno; + + result = stat (filename, &statbuf); + + if (result == 0) { - gchar *display_name = g_filename_display_name (filename); - g_set_error (error, - GTK_FILE_SYSTEM_ERROR, - GTK_FILE_SYSTEM_ERROR_NONEXISTENT, - _("Error getting information for '%s': %s"), - display_name, - g_strerror (ENOENT)); + if (!S_ISDIR (statbuf.st_mode)) + { + result = -1; + code = GTK_FILE_SYSTEM_ERROR_NOT_FOLDER; + my_errno = ENOTDIR; + } + } + else + { + my_errno = errno; - g_free (display_name); - g_free (filename_copy); - return NULL; + if (my_errno == ENOENT) + code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT; + else + code = GTK_FILE_SYSTEM_ERROR_FAILED; } - else if (!g_file_test (filename, G_FILE_TEST_IS_DIR)) + + if (result != 0) { gchar *display_name = g_filename_display_name (filename); g_set_error (error, GTK_FILE_SYSTEM_ERROR, - GTK_FILE_SYSTEM_ERROR_NOT_FOLDER, + code, _("Error getting information for '%s': %s"), display_name, - g_strerror (ENOTDIR)); + g_strerror (my_errno)); g_free (display_name); g_free (filename_copy); @@ -449,16 +460,11 @@ gtk_file_system_unix_get_folder (GtkFileSystem *file_system, folder_unix); } - if ((types & STAT_NEEDED_MASK) && !fill_in_stats (folder_unix, error)) - { - g_object_unref (folder_unix); - return NULL; - } - if ((types & GTK_FILE_INFO_MIME_TYPE) && !fill_in_mime_type (folder_unix, error)) - { - g_object_unref (folder_unix); - return NULL; - } + if ((types & STAT_NEEDED_MASK) != 0) + fill_in_stats (folder_unix); + + if ((types & GTK_FILE_INFO_MIME_TYPE) != 0) + fill_in_mime_type (folder_unix); return GTK_FILE_FOLDER (folder_unix); } @@ -1138,13 +1144,12 @@ get_icon_type_from_path (GtkFileSystemUnix *system_unix, *mime_type = NULL; - if (folder_unix) + if (folder_unix && folder_unix->have_stat) { char *basename; struct stat_info_entry *entry; - if (!fill_in_stats (folder_unix, NULL)) - return ICON_NONE; + g_assert (folder_unix->stat_info != NULL); basename = g_path_get_basename (filename); entry = g_hash_table_lookup (folder_unix->stat_info, basename); @@ -1159,20 +1164,18 @@ get_icon_type_from_path (GtkFileSystemUnix *system_unix, icon_type = entry->icon_type; if (icon_type == ICON_REGULAR) { - (void)fill_in_mime_type (folder_unix, NULL); + fill_in_mime_type (folder_unix); *mime_type = entry->mime_type; } + + return icon_type; } - else - icon_type = ICON_NONE; - } - else - { - icon_type = get_icon_type (filename, NULL); - if (icon_type == ICON_REGULAR) - *mime_type = xdg_mime_get_mime_type_for_file (filename); } + icon_type = get_icon_type (filename, NULL); + if (icon_type == ICON_REGULAR) + *mime_type = xdg_mime_get_mime_type_for_file (filename); + return icon_type; } @@ -1677,78 +1680,89 @@ gtk_file_folder_unix_finalize (GObject *object) folder_parent_class->finalize (object); } +/* Creates a GtkFileInfo for "/" by stat()ing it */ static GtkFileInfo * -gtk_file_folder_unix_get_info (GtkFileFolder *folder, - const GtkFilePath *path, - GError **error) +file_info_for_root_with_error (const char *root_name, + GError **error) { - GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder); + struct stat statbuf; GtkFileInfo *info; - gchar *dirname, *basename; - const char *filename; - struct stat_info_entry *entry; - gboolean file_must_exist; - GtkFileInfoType types; - if (!path) + if (stat (root_name, &statbuf) != 0) { - struct stat buf; + int saved_errno; - g_return_val_if_fail (filename_is_root (folder_unix->filename), NULL); + saved_errno = errno; + g_set_error (error, + GTK_FILE_SYSTEM_ERROR, + GTK_FILE_SYSTEM_ERROR_FAILED, + _("Error getting information for '/': %s"), + g_strerror (saved_errno)); - if (stat (folder_unix->filename, &buf) != 0) - return NULL; + return NULL; + } - info = gtk_file_info_new (); - gtk_file_info_set_display_name (info, "/"); - gtk_file_info_set_is_folder (info, TRUE); - gtk_file_info_set_is_hidden (info, FALSE); - gtk_file_info_set_mime_type (info, "x-directory/normal"); - gtk_file_info_set_modification_time (info, buf.st_mtime); - gtk_file_info_set_size (info, buf.st_size); + info = gtk_file_info_new (); + gtk_file_info_set_display_name (info, "/"); + gtk_file_info_set_is_folder (info, TRUE); + gtk_file_info_set_is_hidden (info, FALSE); + gtk_file_info_set_mime_type (info, "x-directory/normal"); + gtk_file_info_set_modification_time (info, statbuf.st_mtime); + gtk_file_info_set_size (info, statbuf.st_size); - return info; - } + return info; +} - filename = gtk_file_path_get_string (path); - g_return_val_if_fail (filename != NULL, NULL); - g_return_val_if_fail (g_path_is_absolute (filename), NULL); +static gboolean +stat_with_error (const char *filename, + struct stat *statbuf, + GError **error) +{ + if (stat (filename, statbuf) == -1 && + (errno != ENOENT || lstat (filename, statbuf) == -1)) + { + int saved_errno; + int code; + char *display_name; - dirname = get_parent_dir (filename); - g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL); - g_free (dirname); + saved_errno = errno; - basename = g_path_get_basename (filename); - types = folder_unix->types; - file_must_exist = (types & ~GTK_FILE_INFO_DISPLAY_NAME) != 0; - entry = file_must_exist - ? g_hash_table_lookup (folder_unix->stat_info, basename) - : NULL; - /* basename freed later. */ + if (saved_errno == ENOENT) + code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT; + else + code = GTK_FILE_SYSTEM_ERROR_FAILED; - if (!file_must_exist || entry) - { - info = gtk_file_info_new (); - } - else - { - gchar *display_name = g_filename_display_name (filename); + display_name = g_filename_display_name (filename); g_set_error (error, GTK_FILE_SYSTEM_ERROR, - GTK_FILE_SYSTEM_ERROR_NONEXISTENT, - _("Error getting information for '%s'"), - display_name); + code, + _("Error getting information for '%s': %s"), + display_name, + g_strerror (saved_errno)); + g_free (display_name); - info = NULL; - types = 0; + return FALSE; } + return TRUE; +} + +/* Creates a new GtkFileInfo from the specified data */ +static GtkFileInfo * +create_file_info (const char *filename, + const char *basename, + GtkFileInfoType types, + struct stat *statbuf, + const char *mime_type) +{ + GtkFileInfo *info; + + info = gtk_file_info_new (); + if (types & GTK_FILE_INFO_DISPLAY_NAME) { gchar *display_name = g_filename_display_basename (filename); - gtk_file_info_set_display_name (info, display_name); - g_free (display_name); } @@ -1756,22 +1770,125 @@ gtk_file_folder_unix_get_info (GtkFileFolder *folder, gtk_file_info_set_is_hidden (info, basename[0] == '.'); if (types & GTK_FILE_INFO_IS_FOLDER) - gtk_file_info_set_is_folder (info, S_ISDIR (entry->statbuf.st_mode)); + gtk_file_info_set_is_folder (info, S_ISDIR (statbuf->st_mode)); if (types & GTK_FILE_INFO_MIME_TYPE) - gtk_file_info_set_mime_type (info, entry->mime_type); + gtk_file_info_set_mime_type (info, mime_type); if (types & GTK_FILE_INFO_MODIFICATION_TIME) - gtk_file_info_set_modification_time (info, entry->statbuf.st_mtime); + gtk_file_info_set_modification_time (info, statbuf->st_mtime); if (types & GTK_FILE_INFO_SIZE) - gtk_file_info_set_size (info, (gint64)entry->statbuf.st_size); - - g_free (basename); + gtk_file_info_set_size (info, (gint64) statbuf->st_size); return info; } +static struct stat_info_entry * +create_stat_info_entry_and_emit_add (GtkFileFolderUnix *folder_unix, + const char *filename, + const char *basename, + struct stat *statbuf) +{ + GSList *paths; + GtkFilePath *path; + struct stat_info_entry *entry; + + entry = g_new0 (struct stat_info_entry, 1); + + if ((folder_unix->types & STAT_NEEDED_MASK) != 0) + entry->statbuf = *statbuf; + + if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0) + entry->mime_type = g_strdup (xdg_mime_get_mime_type_for_file (filename)); + + g_hash_table_insert (folder_unix->stat_info, + g_strdup (basename), + entry); + + path = gtk_file_path_new_dup (filename); + paths = g_slist_append (NULL, path); + g_signal_emit_by_name (folder_unix, "files-added", paths); + gtk_file_path_free (path); + g_slist_free (paths); + + return entry; +} + +static GtkFileInfo * +gtk_file_folder_unix_get_info (GtkFileFolder *folder, + const GtkFilePath *path, + GError **error) +{ + GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder); + GtkFileInfo *info; + gchar *dirname, *basename; + const char *filename; + GtkFileInfoType types; + struct stat statbuf; + const char *mime_type; + + /* Get_info for "/" */ + if (!path) + { + g_return_val_if_fail (filename_is_root (folder_unix->filename), NULL); + return file_info_for_root_with_error (folder_unix->filename, error); + } + + /* Get_info for normal files */ + + filename = gtk_file_path_get_string (path); + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (g_path_is_absolute (filename), NULL); + + dirname = get_parent_dir (filename); + g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL); + g_free (dirname); + + basename = g_path_get_basename (filename); + types = folder_unix->types; + + if (folder_unix->have_stat) + { + struct stat_info_entry *entry; + + g_assert (folder_unix->stat_info != NULL); + entry = g_hash_table_lookup (folder_unix->stat_info, basename); + + if (!entry) + { + if (!stat_with_error (filename, &statbuf, error)) + { + g_free (basename); + return NULL; + } + + entry = create_stat_info_entry_and_emit_add (folder_unix, filename, basename, &statbuf); + } + + info = create_file_info (filename, basename, types, &entry->statbuf, entry->mime_type); + g_free (basename); + return info; + } + else + { + if (!stat_with_error (filename, &statbuf, error)) + { + g_free (basename); + return NULL; + } + + if ((types & GTK_FILE_INFO_MIME_TYPE) != 0) + mime_type = xdg_mime_get_mime_type_for_file (filename); + else + mime_type = NULL; + + info = create_file_info (filename, basename, types, &statbuf, mime_type); + g_free (basename); + return info; + } +} + static void cb_list_children (gpointer key, gpointer value, gpointer user_data) @@ -1804,7 +1921,6 @@ gtk_file_folder_unix_list_children (GtkFileFolder *folder, l->data = filename_to_path (fullname); g_free (fullname); } - g_signal_emit_by_name (folder_unix, "finished-loading"); return TRUE; } @@ -1831,17 +1947,14 @@ fill_in_names (GtkFileFolderUnix *folder_unix, GError **error) if (folder_unix->stat_info) return TRUE; -#if 0 - g_print ("Reading directory %s\n", folder_unix->filename); -#endif - - folder_unix->stat_info = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify)g_free, - (GDestroyNotify)free_stat_info_entry); dir = g_dir_open (folder_unix->filename, 0, error); if (!dir) return FALSE; + folder_unix->stat_info = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) free_stat_info_entry); + while (TRUE) { const gchar *basename = g_dir_read_name (dir); @@ -1879,24 +1992,20 @@ cb_fill_in_stats (gpointer key, gpointer value, gpointer user_data) } -static gboolean -fill_in_stats (GtkFileFolderUnix *folder_unix, GError **error) +static void +fill_in_stats (GtkFileFolderUnix *folder_unix) { if (folder_unix->have_stat) - return TRUE; + return; - if (!fill_in_names (folder_unix, error)) - return FALSE; + if (!fill_in_names (folder_unix, NULL)) + return; -#if 0 - g_print ("Stating directory %s\n", folder_unix->filename); -#endif g_hash_table_foreach_remove (folder_unix->stat_info, cb_fill_in_stats, folder_unix); folder_unix->have_stat = TRUE; - return TRUE; } @@ -1917,21 +2026,22 @@ cb_fill_in_mime_type (gpointer key, gpointer value, gpointer user_data) return FALSE; } -static gboolean -fill_in_mime_type (GtkFileFolderUnix *folder_unix, GError **error) +static void +fill_in_mime_type (GtkFileFolderUnix *folder_unix) { if (folder_unix->have_mime_type) - return TRUE; + return; + + if (!folder_unix->have_stat) + return; + + g_assert (folder_unix->stat_info != NULL); -#if 0 - g_print ("Getting mime types for directory %s\n", folder_unix->filename); -#endif g_hash_table_foreach_remove (folder_unix->stat_info, cb_fill_in_mime_type, folder_unix); folder_unix->have_mime_type = TRUE; - return TRUE; } static GtkFilePath * -- 2.30.2